package com.eclink.iot.rfid;

import com.eclink.iot.DeviceOnlineStatusListener;
import com.eclink.iot.base.DeviceHealth;
import com.eclink.iot.base.SocketClientBase;
import lombok.extern.slf4j.Slf4j;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

@Slf4j
public class RFIDServer
{
  private final static String TAG = "RFIDServer";
  private static ServerSocket server;
  public static RFIDTagDataListener rfid_tag_data_listener;
  private static DeviceOnlineStatusListener device_online_status_listener;
  private final static Map<String, RFIDDevice> devices = new HashMap<>();
  private final static Runnable process;

  private static final DeviceHealth deviceHealth = new DeviceHealth();
  
  public static void initialization(int port) {
    try {
      server = new ServerSocket(port);
        log.info("{}Server started. Waiting for clients...", TAG);

      // 设备的健康检测开始
        deviceHealth.start();

      (new Thread(process)).start();
    }
    catch (Exception e) {
      log.error("An error occurred", e);
    } 

  }

  // 监听Socket连接
  static {
    process = (() -> {
        while (true) {
          try {
            Socket clientSocket = server.accept();
            log.info("Client connected {}:{}", clientSocket.getRemoteSocketAddress(), clientSocket.getPort());
            (new RFIDDeviceClient(clientSocket)).start();

          } catch (Exception e) {
            log.error("An error occurred", e);
          } 
        }
      });
  }

  public static void on_device_online_status_change(String uuid, int status) {
    device_online_status_listener.notice(uuid, status == 1);
  }

  /**
   * 激活设备
   * 根据服务器中，客户端收到的消息，把设备的状态激活
   * @param uuid UUID
   * @param client 客户端
   */
  public static void activeDevice(String uuid, RFIDDeviceClient client) {

    RFIDDevice device;
    if (devices.containsKey(uuid)) {
        device = devices.get(uuid);
    } else {
      device = new RFIDDevice();
      devices.put(uuid, device);
    }
    device.setUuid(uuid);
    // 更新设备的激活时间
    device.setLastActiveTime(new Date(System.currentTimeMillis()));
    // 把客户端添加到设备中
    device.addClient(client);
    if (device.getStatus()!=1) {
      device.setStatus(1);
      log.info("激活设备：{}", uuid);
      device_online_status_listener.notice(uuid, true);
    }
  }

  /**
   * 释放设备的客户端
   * 设备的客户端不可用了以后，释放设备的客户端，节省资源
   * @param client 客户端
   */
  public static void releaseDeviceClient(RFIDDeviceClient client) {

    for(RFIDDevice device : devices.values()) {
      if (device!=null) {
        device.removeClient(client);
        Set<RFIDDeviceClient> clientList = device.getClientList();
        // 如果设备没有客户端了，就把设备设置为断开
        if (clientList.isEmpty()) {
          device.setStatus(0);
        }
      }
    }

  }

  /**
   * 发送检测设备状态的消息
   */
  public static void sendCheckDeviceStatus() {
    for(RFIDDevice device : devices.values()) {
      if (device!=null) {
        Set<RFIDDeviceClient> clientList = device.getClientList();
        for(RFIDDeviceClient client : clientList) {
          client.get_device_status();
        }
      }
    }
  }

  /**
   * 检测设备的激活状态
   */
  public static void checkDeviceActive() {
    for(RFIDDevice device : devices.values()) {
      device.checkActiveStatus();
    }
  }
  
  public static void set_rfid_tag_data_listener(RFIDTagDataListener listener) {
    rfid_tag_data_listener = listener;
  }
  
  public static void set_device_online_status_listener(DeviceOnlineStatusListener listener) {
    device_online_status_listener = listener;
  }
  
  public static Collection<RFIDDevice> get_online_devices() {
    return RFIDServer.devices.values();
  }

  public static boolean isDeviceActive(String uuid) {
    return RFIDServer.devices.containsKey(uuid);
  }
  
  public static boolean reboot(String uuid) {
    if (devices.containsKey(uuid)) {
      RFIDDevice device = devices.get(uuid);
      Set<RFIDDeviceClient> clientList = device.getClientList();
      for (RFIDDeviceClient client : clientList) {
        client.reboot();
      }
      return true;
    }
    
    return false;
  }
  
  public static boolean inventory(String uuid, int ant) {
    if (devices.containsKey(uuid)) {
      RFIDDevice device = devices.get(uuid);
      Set<RFIDDeviceClient> clientList = device.getClientList();
      for (RFIDDeviceClient client : clientList) {
        client.inventory(ant);
      }
      return true;
    }
    
    return false;
  }
  
  public static boolean inventory_multi(String uuid, int ant) {
    if (devices.containsKey(uuid)) {
      RFIDDevice device = devices.get(uuid);
      Set<RFIDDeviceClient> clientList = device.getClientList();
      for (RFIDDeviceClient client : clientList) {
        client.inventory_multi(ant);
      }
      return true;
    }
    return false;
  }
  
  public static boolean stop(String uuid) {
    if (devices.containsKey(uuid)) {
      RFIDDevice device = devices.get(uuid);
      Set<RFIDDeviceClient> clientList = device.getClientList();
      for (RFIDDeviceClient client : clientList) {
        client.stop_inventory();
      }
      return true;
    }
    
    return false;
  }

  public static boolean upgrade(String uuid) {
    if (devices.containsKey(uuid)) {
      RFIDDevice device = devices.get(uuid);
      Set<RFIDDeviceClient> clientList = device.getClientList();
      byte[] data = new byte[1024];
      for (RFIDDeviceClient client : clientList) {
        client.upgrade(data);
      }
      return true;
    }

    return false;
  }
}
